package org.adream.account.service;

import java.util.HashMap;
import java.util.Properties;
import java.util.Random;

import javax.annotation.Resource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.adream.account.dao.AccountCancelDao;
import org.adream.account.dao.AccountMergeDao;
import org.adream.account.dao.LoginDao;
import org.adream.account.dao.UserDao;
import org.adream.account.entity.AccountCancelEntity;
import org.adream.account.entity.AccountMergeEntity;
import org.adream.account.entity.UserEntity;
import org.adream.account.model.LoginModel;
import org.adream.account.model.ResultModel;
import org.adream.account.util.Constant;
import org.adream.account.util.PasswordUtil;
import org.adream.account.util.SDKTestSendTemplateSMS;
import org.adream.account.util.UserUtil;
import org.adream.account.util.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * 将原先 短信 和 邮箱 验证整合的service
 * 
 * @author chenhaoyu
 *
 */
@Service
public class ValidateService {

	private final static Logger logger = LoggerFactory.getLogger(ValidateService.class);

	private static String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";

	@Value("${mail.from}")
	private String from; // 邮件发送端

	@Value("${mail.licenseCode}")
	private String licenseCode;

	@Value("${mail.smtp.host}")
	private String host;

	@Value("${mail.port}")
	private String port;

	@Autowired
	private HttpSession session;

	@Resource
	private TaskExecutor msgTaskExecutor;
	
	@Autowired 
	UserDao userDao;
	
	@Autowired
	LoginDao loginDao;
	
	@Autowired
	AccountMergeDao accountMergeDao;
	
	@Autowired
	private AccountCancelDao accountCancelDao;
	
	/**
	 * 获取手机验证码
	 * 
	 * @param phone
	 * @param session
	 * @param flag  为5时  是注销账号用 其他不变(改)  
	 * 				为9 时 是合并账户用 其他不变（改）
	 * @return
	 */
	public ResultModel<String> sendIdentifyCodeByPhone(String phone, HttpServletRequest request, Integer flag, String checkCode) {
		logger.info("sendIdentifyCodeByPhone-发送短信验证码");
		HttpSession session = request.getSession();
		// 检测发送短信间隔
		Object before = null;
		if (Constant.NINE == flag) {
			before = session.getAttribute("sendPhoneCodeTimeOfMerge");
		} else if(Constant.FIVE == flag) {
			before = session.getAttribute("sendPhoneCodeTimeOfCancel");			
		} else if(Constant.SIX == flag) {
			before = session.getAttribute("sendPhoneCodeTimeOfAopLogin");			
		} else {
			before = session.getAttribute("sendPhoneCodeTime");
		}

		long now = System.currentTimeMillis();
		if (before != null && (now - (Long) before) < 60000l) {
			logger.warn("验证码操作时间过短:)");
			return new ResultModel<String>(ResultModel.ERR_SERVICE, "验证码操作时间过短", null);
		}
		if (Constant.NINE == flag) {
			session.setAttribute("sendPhoneCodeTimeOfMerge", now);
		} else if(Constant.FIVE == flag) {
			session.setAttribute("sendPhoneCodeTimeOfCancel", now);			
		} else if(Constant.SIX == flag) {
			session.setAttribute("sendPhoneCodeTimeOfAopLogin", now);
		} else {
			session.setAttribute("sendPhoneCodeTime", now);
		}
		
		// 生成随机验证码
		String code = Utils.getNumString();
		if (Constant.NINE == flag) {
			session.setAttribute("phoneCodeOfMerge", code);
		} else if(Constant.FIVE == flag) {
			session.setAttribute("phoneCodeOfCancel", code);		
		} else if(Constant.SIX == flag) {
			// 二次登陆
			session.setAttribute("phoneCodeOfAopLogin", code);		
		} else {
			session.setAttribute("phoneCode", code);
		}
		// 调用接口发送短信
		HashMap<String, Object> result;
		try {
			result = SDKTestSendTemplateSMS.instance.sendMSMinfo(phone, code ,checkCode ,request);
			String statusCode = String.valueOf(result.get("statusCode"));
			
			if (!"000000".equals(statusCode)) {
				String rlt = String.valueOf(result.get("statusMsg"));
				return new ResultModel<String>(ResultModel.ERR_SERVICE, rlt, null);
			}
		} catch (ADreamServiceException e) {
			return new ResultModel<String>(ResultModel.ERR_SERVICE, e.getMessage(), null);
		}
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 获取邮箱验证码
	 * 
	 * @param email
	 * @param session
	 * @return
	 */
	public ResultModel<String> sendIdentifyCodeByEmail(String email, HttpServletRequest request) {
		logger.info("发送邮件!");
		HttpSession session = request.getSession();
		// 检测发送短信间隔
		Object before = session.getAttribute("sendEmailCodeTime");
		long now = System.currentTimeMillis();
		if (before != null && (now - (Long) before) < 60000l) {
			logger.info("验证码操作时间过短:)");
			return new ResultModel<String>(ResultModel.ERR_SERVICE, "验证码操作时间过短", null);
		}
		session.setAttribute("sendEmailCodeTime", now);

		// 生成随机验证码
		String code = Utils.getNumString();
		session.setAttribute("emailCode", code);
		// 调用接口发送邮件

		try {
			// 1.创建属性对象,本质就是属性文件的key-value
			Properties properties = new Properties();
			properties.put("mail.smtp.host", host); // 设置邮件服务器
			properties.put("mail.smtp.port", port);

			properties.put("mail.smtp.socketFactory.class", SSL_FACTORY);
			properties.put("mail.smtp.socketFactory.fallback", "false");
			properties.put("mail.smtp.socketFactory.port", port);
			properties.put("mail.smtp.ssl.enable", "true");
			properties.put("mail.smtp.auth", "true"); // 打开认证

			// 2.由发送者发起会话,并创建认证（发送者邮箱的帐号密码）
			Session verifySession = Session.getDefaultInstance(properties, new Authenticator() {
				public PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(from, licenseCode);
				}
			});

			// 3.创建邮件消息
			Message message = new MimeMessage(verifySession);
			message.setFrom(new InternetAddress(from));
			message.addRecipient(RecipientType.TO, new InternetAddress(email));
			message.setSubject("来自真爱梦想邮箱验证");
			UserEntity user = (UserEntity) session.getAttribute("user");
			String uname = "亲爱的";
			if (!StringUtils.isEmpty(user)) {
				uname += " " + user.getUname() + " ";
			}
			uname += "用户";
			String content = "<h5>" + uname + ",您好:</h5><br/><h5>您正在进行邮箱验证:" + code + "</h5><br/>";
			content += "<h5>请在3分钟内填写,若非您本人操作,请忽略.</h5><br/><h5 align='right'>---真爱梦想</h5><br/>";
			content += "<h5 align='right'>" + Utils.Date2String() + "</h5>";
			message.setContent(content, "text/html;charset=UTF-8");

			msgTaskExecutor.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Transport.send(message);
					} catch (MessagingException e) {
						logger.warn(e.getMessage(), e);
					}
				}
			});
			logger.info("邮件发送成功!");
		} catch (Exception e) {
			logger.info("发送失败 " + e.getMessage());
			return new ResultModel<String>(ResultModel.ERR_SERVICE, e.getMessage(), null);
		}
		
		return new ResultModel<String>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, null);
	}

	/**
	 * 发送梦想老师申请梦想中心主任授权码
	 * 
	 * @param email
	 * @param session
	 * @return
	 */
	public void sendAuthorizationCodeByEmail(String email, String authorizationCode, HttpServletRequest request) throws ADreamServiceException {
		logger.info("发送梦想老师申请梦想中心主任授权码邮件!");
		HttpSession session = request.getSession();
		// 检测发送短信间隔
		Object before = session.getAttribute("sendAuthorizationCodeTime");
		long now = System.currentTimeMillis();
		if (before != null && (now - (Long) before) < 60000l) {
			logger.info("验证码操作时间过短:)");
			throw new ADreamServiceException("验证码操作时间过短");
		}
		session.setAttribute("sendAuthorizationCodeTime", now);

		// 调用接口发送邮件
		try {
			// 1.创建属性对象,本质就是属性文件的key-value
			Properties properties = new Properties();
			properties.put("mail.smtp.host", host); // 设置邮件服务器
			properties.put("mail.smtp.port", port);

			properties.put("mail.smtp.socketFactory.class", SSL_FACTORY);
			properties.put("mail.smtp.socketFactory.fallback", "false");
			properties.put("mail.smtp.socketFactory.port", port);
			properties.put("mail.smtp.ssl.enable", "true");
			properties.put("mail.smtp.auth", "true"); // 打开认证

			// 2.由发送者发起会话,并创建认证（发送者邮箱的帐号密码）
			Session verifySession = Session.getDefaultInstance(properties, new Authenticator() {
				public PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(from, licenseCode);
				}
			});

			// 3.创建邮件消息
			Message message = new MimeMessage(verifySession);
			message.setFrom(new InternetAddress(from));
			message.addRecipient(RecipientType.TO, new InternetAddress(email));
			message.setSubject("来自真爱梦想申请成为梦想中心主任");
			String content = "<h5>【真爱梦想】<br><br>" + "&nbsp;&nbsp;您好！贵校梦想中心已经成立，<br><br>"
					+ "&nbsp;&nbsp;梦想老师在申请成为梦想中心主任时，<br><br>" + "&nbsp;&nbsp;需要唯一授权码：" + authorizationCode
					+ "&nbsp;验证身份。<br><br>" + "&nbsp&nbsp请校长将授权码转发给梦想主任，谢谢！</h5>";
			message.setContent(content, "text/html;charset=UTF-8");

			msgTaskExecutor.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Transport.send(message);
					} catch (MessagingException e) {
						logger.warn(e.getMessage(), e);
					}
				}
			});
			logger.info("邮件发送成功!");
		} catch (Exception e) {
			logger.info("发送失败 " + e.getMessage());
			throw new ADreamServiceException("邮件发送失败:" + e.getMessage());
		}

	}

	/**
	 * 验证手机验证码
	 * 
	 * @param code    输入的验证码
	 * @param request
	 * @return
	 */
	public Boolean verifyPhoneIdentifyCode(String code, HttpServletRequest request) {
		if (StringUtils.isEmpty(code) || StringUtils.isEmpty(code.trim())) {
			logger.warn("验证手机验证码失败,验证码为空");
			return false;
		}
		if (session.getAttribute("phoneCode") != null && code.equals(session.getAttribute("phoneCode"))) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 验证手机验证码  分类型
	 *  只能验证一次  成功后销毁 
	 * @param code    输入的验证码
	 * @param request
	 * @return
	 */
	public Boolean verifyPhoneCodeByType(String code, String type,HttpServletRequest request) {
		if (StringUtils.isEmpty(code) || StringUtils.isEmpty(code.trim())) {
			return false;
		}
		if (session.getAttribute(type) != null && code.equals(session.getAttribute(type))) {
			request.getSession().removeAttribute(type);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 验证邮箱验证码
	 * 
	 * @param code    输入的验证码
	 * @param request
	 * @return
	 */
	public Boolean verifyEmailIdentifyCode(String code, HttpServletRequest request) {
		if (StringUtils.isEmpty(code) || StringUtils.isEmpty(code.trim())) {
			return false;
		}
		Object before = session.getAttribute("sendEmailCodeTime");
		long now = System.currentTimeMillis();
		if (session.getAttribute("emailCode") != null && code.equals(session.getAttribute("emailCode"))
				&& before != null
				// 时效
				&& now - (Long) before < Constant.EMIAL_TOKEN_ALIVE) {
			return true;
		} else {
			return false;
		}
	}

	protected String getNumString() {
		Random r = new Random();
		String num = r.nextInt(9999) + "";
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < 4 - num.length(); i++) {
			sb.append("0");
		}
		num = sb.toString() + num;
		return num;
	}

	public ResultModel<UserEntity> verifyPhoneCodeOfMerge(String phone ,String code, HttpServletRequest request) {
		if (StringUtils.isEmpty(code) || StringUtils.isEmpty(code.trim())) {
			return new ResultModel<UserEntity>(ResultModel.ERR_PARAM, "验证失败,验证码为空", null);
		}
		if(session.getAttribute("phoneCodeOfMerge") == null || !code.equals(session.getAttribute("phoneCodeOfMerge"))) {
			return new ResultModel<UserEntity>(ResultModel.ERR_PARAM, "验证失败,手机验证码错误", null);
		}
		
		UserEntity userEntity = userDao.queryUserByPhone(phone);
		if(userEntity == null || userEntity.getDr() != 1) {
			return new ResultModel<UserEntity>(ResultModel.NOT_FOUND_OBJECT, "验证失败,用户不存在", null);
		}	 
		AccountMergeEntity accountMergeEntity = accountMergeDao.selectMyMerge(userEntity.getUid(), false);
		if(accountMergeEntity !=null) {
			return new ResultModel<UserEntity>(ResultModel.HAS_FOUND_OBJECT, "验证失败,账号合并处理中", null);
		}
		
		String LoginUid = UserUtil.getUidByRequest(request);
		request.getSession().removeAttribute("phoneCodeOfMerge");
		
		if(LoginUid != null && LoginUid.equals(userEntity.getUid())) {
			return new ResultModel<UserEntity>(ResultModel.HAS_FOUND_OBJECT, "验证失败,与当前登录账户相同", null);
		}
		userEntity.setPhone(null);
		return new ResultModel<UserEntity>(ResultModel.SUCCESS, ResultModel.SUCCESS_MSG, userEntity);
	}
	
	// 页面返回user对象   因此用现有的对象 取部分需要的值  
	public ResultModel<?> verifyUnAndPd(String un, String pd, HttpServletRequest request) {
		LoginModel loginModel = loginDao.queryLoginByLogin(un);
		if(loginModel == null) {
			logger.warn("验证出错,未查询到相应的登录信息");
			return new ResultModel<String>(ResultModel.ERR_DATABASE, "无登录信息",null);
		}
		String salt = loginModel.getSalt();
		String password = loginModel.getPassword();
		String uid = loginModel.getUid();
		
		AccountMergeEntity accountMergeEntity = accountMergeDao.selectMyMerge(uid, false);
		if(accountMergeEntity !=null) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, "账号合并处理中", null);
		}
		
		if(StringUtils.isEmpty(password) || StringUtils.isEmpty(uid)
				||StringUtils.isEmpty(password.trim())||StringUtils.isEmpty(uid.trim())) {
			return new ResultModel<String>(ResultModel.ERR_DATABASE, "用户名或密码错误",null);
		}
		if(uid.equals(UserUtil.getUidByRequest(request))) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, "与当前登录账户相同",null);
		}
		
		if(!PasswordUtil.verifyPwd(pd, salt, loginModel.getMethod(), password)) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, "用户名或密码错误",null); 
		}
		UserEntity userEntity = userDao.queryUserByUid(loginModel.getUid());
		UserEntity user = new UserEntity();
		user.setUid(userEntity.getUid());
		user.setHeadimgurl(userEntity.getHeadimgurl());
		user.setUname(userEntity.getUname());
		user.setCts(userEntity.getCts());
		return new ResultModel<UserEntity>(ResultModel.SUCCESS, "登录成功",user); 
	}
	
	/**
	 * 验证账户注销短信登录
	 * @param phone
	 * @param code
	 * @param request
	 * @return
	 */
	public ResultModel<UserEntity> verifyPhoneCodeOfCancel(String phone ,String code, HttpServletRequest request) {
		if (StringUtils.isEmpty(code) || StringUtils.isEmpty(code.trim())) {
			return new ResultModel<UserEntity>(ResultModel.ERR_PARAM, "验证失败,验证码为空", null);
		}
		if(session.getAttribute("phoneCodeOfCancel") == null || !code.equals(session.getAttribute("phoneCodeOfCancel"))) {
			return new ResultModel<UserEntity>(ResultModel.ERR_PARAM, "验证失败,手机验证码错误", null);
		}
		UserEntity userEntity = userDao.queryUserByPhone(phone);
		if(userEntity == null || userEntity.getDr() != 1) {
			return new ResultModel<UserEntity>(ResultModel.NOT_FOUND_OBJECT, "验证失败,用户不存在", null);
		}
		AccountCancelEntity accountCancel = accountCancelDao.queryCancelByCancelUid(userEntity.getUid());
		if(accountCancel != null) {
			return new ResultModel<UserEntity>(ResultModel.HAS_FOUND_OBJECT, "验证失败,账号注销申请已提交", null);
		}
		userEntity.setPhone(null);
		return new ResultModel<UserEntity>(ResultModel.SUCCESS, "登录成功", userEntity); 
	}
	
	// 账号注销页面返回user对象 因此用现有的对象 取部分需要的值
	public ResultModel<?> verifyUnAndPdOfCancel(String un, String pd, HttpServletRequest request) {
		LoginModel loginModel = loginDao.queryLoginByLogin(un);
		if (loginModel == null) {
			logger.warn("验证出错,未查询到相应的登录信息");
			return new ResultModel<String>(ResultModel.ERR_DATABASE, "无登录信息", null);
		}
		String salt = loginModel.getSalt();
		String password = loginModel.getPassword();
		String uid = loginModel.getUid();

		if (StringUtils.isEmpty(password) || StringUtils.isEmpty(uid) || StringUtils.isEmpty(password.trim())
				|| StringUtils.isEmpty(uid.trim())) {
			return new ResultModel<String>(ResultModel.ERR_DATABASE, "用户名或密码错误", null);
		}
		
		if (!PasswordUtil.verifyPwd(pd, salt, loginModel.getMethod(), password)) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, "用户名或密码错误", null);
		}
		
		AccountCancelEntity accountCancel = accountCancelDao.queryCancelByCancelUid(uid);
		if(accountCancel != null && accountCancel.getState() != Constant.THREE) {
			return new ResultModel<String>(ResultModel.ERR_PARAM, "账号注销中或已被注销", null);
		}
		
		UserEntity userEntity = userDao.queryUserByUid(loginModel.getUid());
		UserEntity user = new UserEntity();
		user.setUid(userEntity.getUid());
		user.setHeadimgurl(userEntity.getHeadimgurl());
		user.setUname(userEntity.getUname());
		user.setCts(userEntity.getCts());
		return new ResultModel<UserEntity>(ResultModel.SUCCESS, "登录成功", user);
	}
}